home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / video / xevil-1.000 / xevil-1 / game.C < prev    next >
C/C++ Source or Header  |  1995-08-22  |  64KB  |  2,402 lines

  1. // "game.C"
  2.  
  3. /*    Copyright (C) 1994,1995  Steve Hardt
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     Steve Hardt 
  20.     hardts@athena.mit.edu hardts@media.mit.edu
  21.     hardts@r4002.3dem.bioch.bcm.tmc.edu
  22.     2043 McClendon
  23.     Houston, TX 77030
  24. */
  25.  
  26. #ifndef NO_PRAGMAS
  27. #pragma implementation "game.h"
  28. #endif
  29.  
  30.  
  31. // Include Files
  32. extern "C" {
  33. #include <string.h>
  34. #include <stdio.h>
  35. }
  36.  
  37. #include <strstream.h>
  38. #include <iomanip.h>
  39.  
  40. #include "utils.h"
  41. #include "coord.h"
  42. #include "world.h"
  43. #include "id.h"
  44. #include "intel.h"
  45. #include "physical.h"
  46. #include "actual.h"
  47. #include "locator.h"
  48. #include "ui.h"
  49. #include "game.h"
  50.  
  51. extern "C" {
  52. #include <X11/Xresource.h>
  53. }
  54.  
  55.  
  56.  
  57. // Defines
  58. #define VERSION "1.4"
  59.  
  60. #ifdef XEVIL_KEYSET
  61. #define KEYSET_DEFAULT XEVIL_KEYSET
  62. #else
  63. #define KEYSET_DEFAULT UIdecmips
  64. #endif
  65.  
  66. #ifndef XEVIL_CLASS
  67. #define XEVIL_CLASS "XEvil"
  68. #endif
  69.  
  70. #define WORLD_ACROSS_MAX_DEFAULT 4
  71. #define WORLD_DOWN_MAX_DEFAULT 2
  72.  
  73. #define QUANTA_DEFAULT 40 // In milliseconds
  74. #define QUANTA_MAX 500
  75. #define EXTRA_TURNS 50
  76. #define DEMO_EXTRA_TURNS EXTRA_TURNS
  77. #define OTHER_INPUT_RESET 80
  78. #define HUMANS_NUM_DEFAULT 1
  79. #define ENEMIES_NUM_DEFAULT 3
  80. #define HUMAN_LIVES 3
  81. #define HUMAN_LIVES_SCENARIOS 10
  82. #define REFILL_TIME 200
  83. #define EXTRA_ITEMS_MULTIPLIER 8
  84. #define LEVEL_TIME 3000
  85. #define NEW_LEVEL_TIME 50
  86. #define LEVEL_ENEMIES_INITIAL 3 // Number of enemies on first level.
  87. #define LEVEL_ENEMIES_INCR 2
  88. #define LEVEL_TITLE_TIME 40
  89. #define DEMO_CUTOFF_TIME 400
  90. #define SCENARIO_BONUS_TIME 650
  91. #define SCENARIO_HIVE_ALIENS 15
  92. #define SCENARIO_FLAG_ENEMIES 15
  93. #define SCENARIO_LEMMINGS_ENEMIES 3
  94.  
  95. #define ALTAR_OF_SIN_CHANCE     10
  96. #define PISTOLS_PERCENT         .0004 
  97. #define CHAINSAWS_PERCENT       .0002
  98. #define M_GUNS_PERCENT          .0002
  99. #define SWAPPERS_PERCENT        .0002
  100. #define LANCERS_PERCENT         .0002
  101. #define FROG_GUNS_PERCENT       .0002
  102. #define F_THROWERS_PERCENT      .0002
  103. #define LAUNCHERS_PERCENT       .0002
  104. #define GRENADESS_PERCENT       .0002
  105. #define STARSS_PERCENT          .0002
  106. #define ROCKS_PERCENT           .001 
  107. #define WEIGHTS_PERCENT         .0002
  108. #define MED_KITS_PERCENT        .0003
  109. #define BOMBS_PERCENT           .0006
  110. #define N_SHIELDS_PERCENT       .00008
  111. #define T_SHIELDS_PERCENT       .00008
  112. #define TRANSMOGIFIERS_PERCENT  .00002
  113. #define DOPPELS_PERCENT         .00002 
  114.  
  115.  
  116. char *Game::wittySayings[WITTY_SAYINGS_NUM] = {
  117.   "If it moves it's a threat.  If it doesn't move it's a potential threat.",
  118.     "Happy, happy.  Joy, joy.",
  119.     "For the mother country!!!",
  120.     "Hi ho.  Hi ho.  It's off to kill we go.",
  121.     "Well, do you feel lucky, Punk?",
  122.     "Wake up, time to die.",
  123.     "Let's rock.",
  124.     "I love the smell of napalm in the morning.",
  125.     "How's it feel to be hunted?",
  126.     "Go ahead, make my day.",
  127.     "I'll be back.",
  128.     "Won't you be my neighbor?",
  129.     "3E.  We bring good things to death.",
  130.     "We come in peace.  (Shoot to kill.  Shoot to kill.)",
  131.     "Hey.  You can't do that.",
  132.     "I'm here to chew bubble-gum and kick ass.  And I'm all out of bubble-gum.",
  133.     "You're a useless asshole, Pogo-Man.",
  134.     "Settle down, Beavis.",
  135.     "Ho, ho, ho.  Now I have a machine gun.",
  136.     "Aren't you dead yet?",
  137.     "I don't give a fuck what you know.  I'm going to torture you anyway.",
  138.     "I'm hungry.  Let's get a taco.",
  139.     "I'm sorry, Dave.  I can't do that.",
  140.     "Violence is the only true form of communication.",
  141.     "Let the flames purify your soul!!!",
  142.     "Fuck me gently with a chainsaw.",
  143.     "He doesn't look like a quivering ball of white-hot canine fury.",
  144.     "Hackito ergo sum.",
  145.     "I'm singing in the rain...",
  146.     "Washin' the dog!!  Washin' the dog!!",
  147.     "ooooh.  That's gotta hurt.",
  148.     "Kids, don't try this at home.  We're trained professionals.",
  149.     "Oh, you want some of this?!  Fuck you!",
  150.     "Well, he shoulda' armed himself!",
  151.     "Fuck art.  Let's kill.",
  152.     "If you can't eat it or fuck it, kill it.",
  153.     "Skrotus lives in my fridge.",
  154.     "I love you.  You love me.  We're a happy family.",
  155.     "You always were an asshole, Gorman.",
  156.     "Change it dude.  This sucks.",
  157.     "The game of death, doom, and (more or less) ultimate destruction.",
  158.     "I think I'll just Dieeeeeee.",
  159.     "You know he'll feel that one in the morning.",
  160.     "I've had this ice-cream bar since I was a child.",
  161.     "Shut up or I will kill you.  I will physically kill you.",
  162.     "Better stop before someone gets hurt.",
  163.     "What??",
  164.     "Whoa!!",
  165.     "Jesus will love you if you give me money.",
  166.     "Evil.  It's not just for breakfast anymore.",
  167.     "XEvil.  The carpal tunnel game.",
  168.     "Violence.  It's not just the best policy.  It's the only policy.",
  169.     "Got ... to get ... to ... my arm.",
  170.     "Who's the lucky one?",
  171.     "Don't blink.  It would really suck if you blinked.",
  172.     "Here kitty, kitty, kitty.",
  173.     "Stay on target...",
  174.     "Do not taunt Happy-Fun-Ball.",
  175.     "Bring out the gimp.                            Gimp's sleepin.\nWell, I guess you'll just have to go wake him up now, won't you.",
  176.     "That's easy.",
  177.     "It's just a rabbit.",
  178.     "Ignorance is the number one cause of happiness.",
  179.     "What the heck's going on?  I thought I was a normal guy.",
  180.     "Oh, no.  It's K-k-k-ken c-c-c-coming to k-k-k-kill me.",
  181.     "You bloated sack of protoplasm.",
  182.     "The weak exist only to amuse the strong.",
  183.     "We're not hitch-hiking anymore.  We're riding.",
  184.     "No, sir.  I didn't like it.",
  185.     "Are we there yet?",
  186.     "Kurt Cobain spoke for my generation.",
  187.     "We're on a mission from God.",
  188.     "Oh, I'm a lumberjack and I'm ok...",
  189.     "I'm sorry.  You must have mistaken me for the clown that gives a damn.",
  190.     "Another visitor.  Stay awhile.  STAY FOREVER!!!!",
  191.     "I laughed.  I cried.  It was better than Cats.\nI'd see it again and again.",
  192.     "SPOON!!!",
  193.     "Only life can kill you.",
  194.     "That which does not kill us, hurts.",
  195.     "Hey, baby.  Wanna wrestle.",
  196.     "Fuck you and the horse you rode in on.",
  197.     "Spin, spin, spin, spin, spin, spin, spin...",
  198.     "Dope will get you through times of no money\nbetter than money will get you through times of no dope.",
  199.     "What he said.",
  200.     "Like, take off, eh.",
  201.     "Lord God, Leroy, that was the toughest meanest hippie I ever saw.",
  202.     "Happy thoughts.  Happy thoughts. Happy thoughts.",
  203.     "M*cr*s*ft:  Who need quality when you have marketing.",
  204.     "The proof is left as an exercise.",
  205.     "Ummm...  We have a problem.",
  206.     "Come see the violence inherent in the system.\nHelp! Help! I'm being repressed.",
  207.     "Hey, man, you a sniper?                                           Shut up.\nYou sure look like a sniper.                                      I said, shut up.",
  208.     "Oh, I'm sorry.  Did that hurt?",
  209.     "What me worry?",
  210.     "Nobody expects the Spanish Inquisition!!!",
  211.     "We are, we are, we are, we are, we are the engineers.\nWe can, we can, we can, we can demolish forty beers.",
  212.     "When in doubt, shoot the lawyer.",
  213.     "All that hate's gonna burn you up, boy.\nKeeps me warm.",
  214.     "He lives in that piece of paper?\nNo, you idiot.  He lives in a regular house.",
  215.     "I'll give you something to cry about.",
  216.     "It's not a bug, it's a feature.",
  217.     "Don't hate me because I'm beautiful.",
  218.     "What a great game of cards this is.",
  219.     "You're ugly and your mother dresses you funny.",
  220. };
  221.  
  222.  
  223.  
  224. char *Game::intelNames[INTEL_NAMES_NUM] = {
  225.   "Dr. Pain",
  226.   "Steve",
  227.   "hardts",
  228.   "James E. Tetazoo",
  229.   "Arnold",
  230.   "Victor the Cleaner",
  231.   "Hudson",
  232.   "Hicks",
  233.   "Twinkie Boy",
  234.   "Bob",
  235.   "Ben Bitdiddle",
  236.   "Beavis",
  237.   "Butt-Head",
  238.   "Fred",
  239.   "Mulch-Man",
  240.   "Mike",
  241.   "Tim",
  242.   "Peter",
  243.   "Alan",
  244.   "Neal",
  245.   "Tony",
  246.   "Asshole",
  247.   "Crazy Hairy",
  248.   "Spaceman Spiff",
  249.   "Kitty-Wench",
  250.   "Juker",
  251.   "Shrieks",
  252.   "Albert Lin",
  253.   "Jim Gouldstone",
  254.   "Steph",
  255.   "Paining",
  256.   "Dim",
  257.   "The Man",  
  258.   "Twinkie Girl",
  259.   "Mr. Buzzcut",  
  260.   "Sensei Steve",
  261.   "Ren",
  262.   "Stimpy",
  263.   "Mr. Horse",
  264.   "Dilbert",
  265.   "Dogbert",
  266.   "Gromit",
  267.   "The Tick",
  268.   "Fat Freddie",
  269.   "Phineas",
  270.   "Freewheelin Franklin",
  271.   "Doctor Who",
  272.   "Celery-Head-Man",
  273.   "Roo",
  274.   "Shwang",
  275.   "Leo",
  276.   "Smoothie",
  277.   "Hawaii Chick",
  278.   "Cowboy Steve",
  279.   "Outlaw Jim",
  280.   "Prick",
  281.   "Smack",
  282.   "Hello, Kitty",
  283.   "Wedge",
  284.   "Redshirt",
  285. };
  286.  
  287.  
  288.  
  289.  
  290. // Functions     
  291. void GameStats::report()
  292. {
  293.   if (numTurns % Game::REPORT_TIME == 0)
  294.     cout << "Turn " << numTurns << ":  Average time of turn:  " << 
  295.       aveTime << endl;
  296. }
  297.  
  298.  
  299.  
  300. void GameStats::clock()
  301. {
  302.   time_t oldPrevTime = prevTime;
  303.   time(&prevTime);    
  304.  
  305.   if (numTurns)
  306.     aveTime = (numTurns * aveTime + (prevTime - oldPrevTime)) / 
  307.       (numTurns + 1); 
  308.   
  309.   numTurns++;
  310. }
  311.  
  312.  
  313.  
  314. GameObjects::GameObjects(Boolean pol_correct)
  315. {
  316.   resetCalled = False;
  317.   for (int n = 0; n < HIGHEST; n++)
  318.     ids[n] = NULL;
  319.   polCorrect = pol_correct;
  320. }
  321.  
  322.  
  323.  
  324. void GameObjects::game_reset(const char *one_item,
  325.                  Boolean no_items,Boolean one_each)
  326. {
  327.   oneItem = one_item;
  328.   noItems = no_items;
  329.   oneEach = one_each;
  330.   resetCalled = True;
  331.   altarOfSinAlready = noItems; // If noItems, don't want an Altar of Sin.
  332.   
  333. //  level_reset(worldDim);
  334. }
  335.  
  336.  
  337.  
  338. void GameObjects::level_reset(const Dim &worldDim)
  339. {
  340.   // WARNING: GameObjects forgets about old items.  Not a memory leak, but 
  341.   // this may end up with more and more items coming into existence.
  342.  
  343.   // Initialization.
  344.   for (int n = 0; n < HIGHEST; n++)
  345.     {
  346.       maximums[n] = 0;
  347.       if (ids[n])
  348.     delete [] ids[n];
  349.     }
  350.  
  351.   // Normal case.
  352.   if (!strlen(oneItem) && !noItems && !oneEach)
  353.     {
  354.       int area = worldDim.rowMax * worldDim.colMax;
  355.  
  356.       maximums[PISTOLS] = (int)ceil(area * PISTOLS_PERCENT);
  357.       maximums[CHAINSAWS] = (int)ceil(area * CHAINSAWS_PERCENT);
  358.       maximums[M_GUNS] = (int)ceil(area * M_GUNS_PERCENT);
  359.       maximums[SWAPPERS] = (int)ceil(area * SWAPPERS_PERCENT);
  360.       maximums[LANCERS] = (int)ceil(area * LANCERS_PERCENT);
  361.       maximums[FROG_GUNS] = (int)ceil(area * FROG_GUNS_PERCENT);
  362.       maximums[F_THROWERS] = (int)ceil(area * F_THROWERS_PERCENT);
  363.       maximums[LAUNCHERS] = (int)ceil(area * LAUNCHERS_PERCENT);
  364.       maximums[GRENADESS] = (int)ceil(area * GRENADESS_PERCENT);
  365.       maximums[STARSS] = (int)ceil(area * STARSS_PERCENT);
  366.       maximums[ROCKS] = (int)ceil(area * ROCKS_PERCENT);
  367.       maximums[WEIGHTS] = (int)ceil(area * WEIGHTS_PERCENT);
  368.       maximums[MEDKITS] = (int)ceil(area * MED_KITS_PERCENT);
  369.       maximums[BOMBS] = (int)ceil(area * BOMBS_PERCENT);
  370.       maximums[N_SHIELDS] = (int)ceil(area * N_SHIELDS_PERCENT);
  371.       maximums[T_SHIELDS] = (int)ceil(area * T_SHIELDS_PERCENT);
  372.       maximums[TRANSMOGIFIERS] = (int)ceil(area * TRANSMOGIFIERS_PERCENT);
  373.       maximums[DOPPELS] = (int)ceil(area * DOPPELS_PERCENT);
  374.     }
  375.   // Only one item in the Game.
  376.   else if (strlen(oneItem))
  377.     {
  378.       if (!strcmp("rock",oneItem))
  379.     maximums[ROCKS] = 1;
  380.       else if (!strcmp("weight",oneItem))
  381.     maximums[WEIGHTS] = 1;
  382.       else if (!strcmp("med-kit",oneItem))
  383.     maximums[MEDKITS] = 1;
  384.       else if (!strcmp("bomb",oneItem))
  385.     maximums[BOMBS] = 1;
  386.       else if (!strcmp("chainsaw",oneItem))
  387.     maximums[CHAINSAWS] = 1;
  388.       else if (!strcmp("pistol",oneItem))
  389.     maximums[PISTOLS] = 1;
  390.       else if (!strcmp("machine-gun",oneItem))
  391.     maximums[M_GUNS] = 1;
  392.       else if (!strcmp("soul-swapper",oneItem))
  393.     maximums[SWAPPERS] = 1;
  394.       else if (!strcmp("lancer",oneItem))
  395.     maximums[LANCERS] = 1;
  396.       else if (!strcmp("frog-gun",oneItem))
  397.     maximums[FROG_GUNS] = 1;
  398.       else if (!strcmp("flame-thrower",oneItem))
  399.     maximums[F_THROWERS] = 1;
  400.       else if (!strcmp("launcher",oneItem))
  401.     maximums[LAUNCHERS] = 1;
  402.       else if (!strcmp("grenades",oneItem))
  403.     maximums[GRENADESS] = 1;
  404.       else if (!strcmp("stars",oneItem))
  405.     maximums[STARSS] = 1;
  406.       else if (!strcmp("n-shield",oneItem))
  407.     maximums[N_SHIELDS] = 1;
  408.       else if (!strcmp("t-shield",oneItem))
  409.     maximums[T_SHIELDS] = 1;
  410.       else if (!strcmp("transmogifier",oneItem))
  411.     maximums[TRANSMOGIFIERS] = 1;
  412.       else if (!strcmp("doppelganger",oneItem))
  413.     maximums[DOPPELS] = 1;
  414.     }
  415.   // One of each object.
  416.   else if (oneEach)
  417.     for (n = 0; n < HIGHEST; n++)
  418.       maximums[n] = 1;
  419.  
  420.   // Create the arrays of ids for each object type.
  421.   for (n = 0; n < HIGHEST; n++)
  422.     {
  423.       Id invalid;
  424.       ids[n] = new Id[maximums[n]];
  425.       for (int m = 0; m < maximums[n]; m++)
  426.     ids[n][m] = invalid;
  427.       // Explicitly initialize ids because different C++ compilers follow
  428.       // different rules about constructing elements of an array.
  429.     }
  430.  
  431.   // Compute actuals from maximums.
  432.   compute_actuals();
  433.  
  434.   // Somewhat of a hack.  Always want maximum number when using oneItem or
  435.   // oneEach.
  436.   if (strlen(oneItem) || oneEach)
  437.     for (n = 0; n < HIGHEST; n++)
  438.       actuals[n] = maximums[n];
  439. }
  440.  
  441.  
  442.  
  443. // Really should be a template.
  444. /* EFFECTS:  Choose a random number < maximum and make sure at least that many
  445.    of the item exist. */
  446. #define REFILL_HELPER(CLASS,which)\
  447. {\
  448.   int existsNum = 0;\
  449.   PhysicalP dummy;\
  450.   for (int m = 0; m < maximums[which]; m++)\
  451.     if (locator->lookup(dummy,ids[which][m]) == OL_NO_SIG)\
  452.       existsNum++;\
  453.   int newOnes = actuals[which] - existsNum;\
  454.   for (m = 0; newOnes > 0; m++)\
  455.     {\
  456.       assert(m < maximums[which]);\
  457.       if (locator->lookup(dummy,ids[which][m]) == OL_NOT_FOUND)\
  458.     { \
  459.       Pos pos = world->empty_rect(CLASS::get_size_max());\
  460.       PhysicalP p = new CLASS(world,locator,pos);\
  461.       assert(p);\
  462.       locator->add(p);\
  463.       ids[which][m] = p->get_id();\
  464.       newOnes--;\
  465.     }\
  466.     }\
  467. }
  468.  
  469. void GameObjects::refill(WorldP world,LocatorP locator)
  470. {
  471.   assert(resetCalled);
  472.  
  473.   if (!polCorrect && !altarOfSinAlready && 
  474.       Utils::choose(ALTAR_OF_SIN_CHANCE) == 0)
  475.     {
  476.       Pos pos = world->empty_rect(AltarOfSin::get_size_max());
  477.       PhysicalP p = new AltarOfSin(world,locator,pos); 
  478.       assert(p); 
  479.       locator->add(p); 
  480.       altarOfSinAlready = True;
  481.     }
  482.       
  483.   REFILL_HELPER(Rock,ROCKS);
  484.   REFILL_HELPER(Weight,WEIGHTS);
  485.   REFILL_HELPER(MedKit,MEDKITS);
  486.   REFILL_HELPER(Bomb,BOMBS);
  487.   REFILL_HELPER(Chainsaw,CHAINSAWS);
  488.   REFILL_HELPER(Pistol,PISTOLS);
  489.   REFILL_HELPER(MGun,M_GUNS);
  490.   REFILL_HELPER(Swapper,SWAPPERS);
  491.   REFILL_HELPER(Lancer,LANCERS);
  492.   REFILL_HELPER(FrogGun,FROG_GUNS);
  493.   REFILL_HELPER(FThrower,F_THROWERS);
  494.   REFILL_HELPER(Launcher,LAUNCHERS);
  495.   REFILL_HELPER(Grenades,GRENADESS);
  496.   REFILL_HELPER(Stars,STARSS);
  497.   REFILL_HELPER(NShield,N_SHIELDS);
  498.   REFILL_HELPER(TShield,T_SHIELDS);
  499.   REFILL_HELPER(Transmogifier,TRANSMOGIFIERS);
  500.   REFILL_HELPER(Doppel,DOPPELS);
  501. }
  502. #undef REFILL_HELPER
  503.  
  504.  
  505.  
  506. void GameObjects::compute_actuals()
  507. {
  508.   const int O_HIGHEST = HIGHEST - W_HIGHEST;
  509.  
  510.   // Initialize all actuals to 0.
  511.   for (int n = 0; n < HIGHEST; n++)
  512.     actuals[n] = 0;
  513.  
  514.   // Number of weapon and other classes to include in this level.
  515.   int wClassesNum = 2 + Utils::choose(5);  // 2 <= wClassesNum <= 6
  516.   int oClassesNum = 1 + Utils::choose(5);  // 1 <= oClassesNum <= 5
  517.   assert(wClassesNum < W_HIGHEST && oClassesNum < O_HIGHEST);
  518.  
  519.   // Rank the weapon and other classes.
  520.   int wRank[W_HIGHEST];
  521.   Utils::randomList(wRank,W_HIGHEST);
  522.   int oRank[O_HIGHEST];
  523.   Utils::randomList(oRank,O_HIGHEST);
  524.  
  525.   // Set actuals to be non-zero for the first wClassesNum in wRank.
  526.   for (n = 0; n < wClassesNum; n++)
  527.     {
  528.       int which = wRank[n];
  529.       actuals[which] = 
  530.     maximums[which] ? (Utils::choose(maximums[which]) + 1) : 0;
  531.     }
  532.  
  533.   // Set actuals to be non-zero for the first oClassesNum in oRank.
  534.   for (n = 0; n < oClassesNum; n++)
  535.     {
  536.       int which = oRank[n] + W_HIGHEST;
  537.       actuals[which] = 
  538.     maximums[which] ? (Utils::choose(maximums[which]) + 1) : 0;
  539.     }
  540. }
  541.  
  542.  
  543.  
  544. Game::Game(int *arg_c,char **arg_v)
  545.      : world(is_pol_correct(arg_c,arg_v)), 
  546.        locator(&world),
  547.        ui(arg_c,arg_v,&world,&locator,display_names(arg_c,arg_v),
  548.       is_pol_correct(arg_c,arg_v)),
  549.        gameObjects(is_pol_correct(arg_c,arg_v))
  550.   polCorrect = is_pol_correct(arg_c,arg_v);
  551.  
  552.   argc = arg_c;
  553.   argv = arg_v;
  554.  
  555.   gameOn = False;
  556.   demoOn = True;
  557.  
  558.   Timer t1(EXTRA_TURNS);
  559.   extraTimer = t1;
  560.   extraTime = False;
  561.  
  562.   Timer t11(DEMO_EXTRA_TURNS);
  563.   demoExtraTimer = t11;
  564.   demoExtraTime = False;
  565.  
  566.   Timer t2(OTHER_INPUT_RESET);
  567.   otherInputReset = t2;
  568.  
  569.   Timer t3(REFILL_TIME);
  570.   refillTimer = t3;
  571.   refillTimer.set();
  572.  
  573.   newLevelTime = False;
  574.  
  575.   Timer t5(LEVEL_TITLE_TIME);
  576.   levelTitleTimer = t5;
  577.   levelTitleTime = False;
  578.  
  579.   Timer t6(DEMO_CUTOFF_TIME);
  580.   demoCutoffTimer = t6;
  581.  
  582.   pause = False;
  583.   style = styleNext = UIsettings::LEVELS;
  584.   ui.set_style(style);
  585.  
  586.   scenarioOverride = HIGHEST; // I.e. ignore the override. 
  587.  
  588.   humansNum = 0;
  589.   humansNumNext = HUMANS_NUM_DEFAULT;
  590.   ui.set_humans_num(humansNumNext);
  591.  
  592.   enemiesNum = 0;
  593.   // Must be before parse_args.
  594.   enemiesNumNext = ENEMIES_NUM_DEFAULT;
  595.   ui.set_enemies_num(enemiesNumNext);
  596.  
  597.   enemiesRefill = enemiesRefillNext = False;
  598.   ui.set_enemies_refill(False);
  599.  
  600.   quanta = QUANTA_DEFAULT;
  601.   ui.set_quanta(quanta);
  602.  
  603.   humansPlayingPrev = enemiesPlayingPrev = 0;
  604.   enemyNameCount = 0;
  605.  
  606.   worldRooms.downMax = WORLD_DOWN_MAX_DEFAULT;
  607.   worldRooms.acrossMax = WORLD_ACROSS_MAX_DEFAULT;
  608.  
  609.   intelHarmless = False;
  610.   showStats = False;
  611.   dontAdvance = False;
  612.  
  613.   noItems = False;
  614.   oneEach = False;
  615.   oneItem = "";
  616.  
  617.   humanClass = A_None;
  618.  
  619.   parse_args(argc,argv);
  620.  
  621.   // Now in Game::reset.
  622.   // world.set_rooms_next(worldRooms);
  623.  
  624.   // Must be before first call to Ui::set_input.
  625.   process_x_resources(argc,argv);            
  626.   ui.set_input(0,UI_KEYS_RIGHT);
  627.  
  628.   intro();
  629.   locator.set_messages_ignore(True); // Must be after intro().
  630.  
  631.   demoCutoffTimer.set();
  632.   demo_setup();
  633. }
  634.  
  635.  
  636.  
  637. void Game::clock()
  638. {
  639.   Boolean shouldReset = False;
  640.  
  641.   ui_settings_check(shouldReset);
  642.   
  643.   // Must be before ui.clock().
  644.   if (!pause && !gameOn && otherInputReset.ready() && ui.other_input())
  645.     shouldReset = True;
  646.   
  647.   ui.clock();
  648.   
  649.   if (!pause)
  650.     {
  651.       /* Put after ui.clock so doesn't draw screen twice on reset.  Intel needs
  652.      to be clocked to get id so that ui can follow the id of the intel. */
  653.       if (shouldReset)
  654.     reset();
  655.       
  656.       if (gameOn)
  657.     {
  658.       if (levelTitleTime)
  659.         {
  660.           levelTitleTimer.clock();
  661.           if (levelTitleTimer.ready())
  662.         {
  663.           ui.unset_level_title();
  664.           levelTitleTime = False;
  665.         }
  666.         }
  667.       else
  668.         {
  669.           world.clock();
  670.           locator.clock();  
  671.           
  672.           reincarnations_check();
  673.           
  674.           int humansPlaying = locator.humans_playing();
  675.           int enemiesPlaying = locator.enemies_alive();
  676.           
  677.           if (humansPlaying != humansPlayingPrev)
  678.         {
  679.           humansPlayingPrev = humansPlaying;
  680.           ui.set_humans_playing(humansPlaying);
  681.         }
  682.           
  683.           if (enemiesPlaying != enemiesPlayingPrev)
  684.         {
  685.           enemiesPlayingPrev = enemiesPlaying;
  686.           ui.set_enemies_playing(enemiesPlaying);
  687.         }
  688.  
  689.           game_over_check(humansPlaying,enemiesPlaying);
  690.           
  691.           new_level_check(enemiesPlaying);
  692.           
  693.           if (showStats)
  694.         stats.report();
  695.           stats.clock();
  696.  
  697.           refill_check();
  698.  
  699.         } /* if (levelTitleTime) */
  700.     } /* if (gameOn) */
  701.       else
  702.     {
  703.       otherInputReset.clock();
  704.       demo_check();
  705.     }
  706.     } /* if (!pause) */
  707. }
  708.  
  709.  
  710.  
  711. void Game::ui_settings_check(Boolean &shouldReset)
  712. {
  713.   if (ui.settings_changed())
  714.     {
  715.       UIsettings settings;
  716.       UImask mask = ui.get_settings(settings);
  717.       
  718.       if (mask & UInewGame)
  719.     shouldReset = True;
  720.  
  721.       if (mask & UIquit)
  722.     {
  723.       print_stats();
  724.       exit(0);
  725.     }
  726.  
  727.       if (mask & UIhumansNum)
  728.     {
  729.       humansNumNext = min(settings.humansNum,Locator::HUMANS_MAX);
  730.       ui.set_humans_num(humansNumNext);
  731.     }
  732.  
  733.       if (mask & UIenemiesNum)
  734.     {
  735.       enemiesNumNext = min(settings.enemiesNum,Locator::ENEMIES_MAX);
  736.       ui.set_enemies_num(enemiesNumNext);
  737.     }
  738.  
  739.       if (mask & UIenemiesRefill)
  740.     {
  741.       enemiesRefillNext = settings.enemiesRefill;
  742.       ui.set_enemies_refill(enemiesRefillNext);
  743.     }
  744.  
  745.       if (mask & UIpause)
  746.     {
  747.       pause = settings.pause;
  748.       ui.set_pause(pause);
  749.     }
  750.  
  751.       if (mask & UIstyle)
  752.     {
  753.       ostrstream str;
  754.       styleNext = settings.style;
  755.       ui.set_style(settings.style);
  756.       switch (styleNext) {
  757.       case UIsettings::SCENARIOS:
  758.         str << "A number of different scenarios." << "\n"
  759.         << "You must complete each scenario to continue on to the "
  760.         << "next one." << ends;
  761.         break;
  762.       case UIsettings::LEVELS:
  763.         str << "Human player(s) fights through increasing levels of "
  764.         << "difficulty." << "\n" 
  765.         << "To complete a level you must kill all enemy players." 
  766.         << ends;
  767.         break;
  768.       case UIsettings::KILL:
  769.         str << "Every human and machine for him/her/itself." << ends;
  770.         break;
  771.       case UIsettings::DUEL:
  772.         str << "Human vs. human battle to the death." 
  773.         << "\n" << "Each human has 3 lives." << ends;
  774.         break;
  775.       case UIsettings::EXTENDED:
  776.         str << "Human vs. human battle to the death." 
  777.         << "\n" << "Unlimited lives." << ends;
  778.         break;
  779.       case UIsettings::TRAINING:
  780.         str << "One human plays alone.  Useful for learning the "
  781.         << "controls." << ends;
  782.         break;
  783.       };
  784.       locator.message_enq(str.str());
  785.     }
  786.       
  787.       if (mask & UIquanta)
  788.     {
  789.       quanta = settings.quanta;
  790.       if (quanta < 0)
  791.         quanta = 0;
  792.       if (quanta > QUANTA_MAX)
  793.         quanta = QUANTA_MAX;
  794.       ui.set_quanta(quanta);
  795.     }
  796.     }
  797. }
  798.  
  799.  
  800.  
  801. void Game::reincarnations_check()
  802. {
  803.   Incarnator iter(locator);
  804.   HumanP human;
  805.   while (human = iter())
  806.     {
  807.       PhysicalP obj = human_physical();
  808.       locator.add(obj);
  809.       human->reincarnate();
  810.       obj->set_intel(human);
  811.       
  812.       ostrstream msg;
  813.       msg << human->get_name() << " is back from the dead." << ends;
  814.       locator.message_enq(msg.str());
  815.     }
  816. }
  817.  
  818.  
  819.  
  820. void Game::game_over_check(int humansPlaying,int enemiesPlaying)
  821. {
  822.   if (!extraTime && 
  823.       (((style == UIsettings::SCENARIOS || 
  824.      style == UIsettings::LEVELS) && 
  825.     humansPlaying == 0) ||
  826.        (style == UIsettings::KILL && 
  827.     humansPlaying + enemiesPlaying <= 1) ||
  828.        ((style == UIsettings::DUEL || 
  829.      style == UIsettings::EXTENDED) &&
  830.     humansPlaying <= 1) ||
  831.        (style == UIsettings::TRAINING &&
  832.     humansPlaying == 0)))
  833.     {
  834.       // End the game.
  835.       extraTime = True;
  836.       extraTimer.set();
  837.     }
  838.  
  839.   if (extraTime && extraTimer.ready())
  840.     end_game();
  841.   if (extraTime)
  842.     extraTimer.clock();
  843. }      
  844.  
  845.  
  846.  
  847. void Game::new_level_check(int enemiesPlaying)
  848. {
  849.   if (style == UIsettings::SCENARIOS)
  850.     {
  851.       if (!newLevelTime && scenario == EXTERMINATE && enemiesPlaying == 0)
  852.     {
  853.       newLevelTime = True;
  854.       newLevelTimer.set(NEW_LEVEL_TIME);
  855.     }
  856.       else if (scenario == BONUS)
  857.     {
  858.       // Count number of Frogs still alive.
  859.       int remaining = 0;
  860.       for (int n = 0; n < SCENARIO_BONUS_FROGS; n++)
  861.         {
  862.           PhysicalP p = locator.lookup(frogs[n]);
  863.           if (p && p->alive())
  864.         remaining++;
  865.         }
  866.       
  867.       // Update Ui.
  868.       if (remaining != frogsRemaining)
  869.         {
  870.           frogsRemaining = remaining;
  871.           ostrstream str;
  872.           str << "[" << level << "] BONUS LEVEL\nfrogs remaining: " 
  873.         << remaining << ends;
  874.           ui.set_level(str.str());
  875.           delete str.str();
  876.  
  877.           // Will only be called once per level.
  878.           if (frogsRemaining == 0)
  879.         {
  880.           ostrstream ostr;
  881.           ostr << "***** You must feel proud of yourself for killing all those defenseless frogs. *****" << ends;
  882.           locator.message_enq(ostr.str());
  883.           assert(newLevelTime);
  884.           newLevelTimer.set(NEW_LEVEL_TIME);
  885.         }
  886.         }      
  887.     }
  888.       else if (!newLevelTime && scenario == HIVE)
  889.     {
  890.       PhysicalP xit = locator.lookup(xitId);
  891.       assert(xit); // The Xit should never be destroyed.
  892.       if (((TouchableP)xit)->wasTouched())
  893.         {
  894.           newLevelTimer.set(0);
  895.           newLevelTime = True;
  896.         }
  897.     }
  898.       else if (!newLevelTime && scenario == FLAG)
  899.     {
  900.       int fRemaining = 0;
  901.       for (int n = 0; n < SCENARIO_FLAG_FLAGS; n++)
  902.         {
  903.           PhysicalP p = locator.lookup(flagIds[n]);
  904.           if (p)
  905.         {
  906.           fRemaining++;
  907.           if (((TouchableP)p)->wasTouched())
  908.             off_clock_kill(p);
  909.         }
  910.         }
  911.       if (fRemaining == 0) // All flags are gone, so end level.
  912.         {
  913.           newLevelTime = True;
  914.           newLevelTimer.set(0);
  915.         }
  916.       if (fRemaining != flagsRemaining)
  917.         {
  918.           flagsRemaining = fRemaining;
  919.           ostrstream levelStr;
  920.           levelStr << "[" << level << "] COLLECT " << SCENARIO_FLAG_FLAGS
  921.         << " FLAGS\nremaining: " << flagsRemaining << ends;
  922.           ui.set_level(levelStr.str()); 
  923.           delete levelStr.str();
  924.         }
  925.     }
  926.       else if (!newLevelTime && scenario == LEMMINGS)
  927.     {
  928.       // NOTE: Lemming counts may be a little screwy if other Physicals
  929.       // have soul-swapped with some of the Lemmings.  
  930.       
  931.       HomeP home = (HomeP)locator.lookup(homeId);
  932.       TrapdoorP trapdoor = (TrapdoorP)locator.lookup(trapdoorId);
  933.       assert(home && trapdoor);
  934.  
  935.       // Count lemmings out, active, and safe.
  936.       IntelId *lemmings; // Care about LemmingIntels, not Lemmings.
  937.       int lemOut = trapdoor->get_lemmings_out(lemmings);
  938.       int lemSafe = home->get_lemmings_safe();
  939.       int lemActive = 0;
  940.       for (int n = 0; n < lemOut; n++)
  941.         {
  942.           IntelP lemmingIntel = locator.lookup(lemmings[n]);          
  943.           if (lemmingIntel)
  944.         {
  945.           PhysicalP lemming = locator.lookup(lemmingIntel->get_id());
  946.           if (lemming && lemming->alive())
  947.             lemActive++;
  948.         }
  949.         }
  950.  
  951.       // Number Dead depends only on Out, Safe, and Active, so don't bother
  952.       // keeping it from turn to turn.  I.e. no Game::lemmingsDead.
  953.       int lemDead = lemOut - lemSafe - lemActive;
  954.       
  955.       // Update the Ui if necessary.
  956.       if (lemSafe != lemmingsSafe || lemOut != lemmingsOut ||
  957.           lemActive != lemmingsActive)
  958.         {
  959.           lemmingsSafe = lemSafe;
  960.           lemmingsOut = lemOut;
  961.           lemmingsActive = lemActive;
  962.           ostrstream levelStr;
  963.           levelStr << "[" << level << "] SAVE " 
  964.         << SCENARIO_LEMMINGS_NEED << " LEMS\n" 
  965.           << "out: " << lemmingsOut << " safe: " << lemmingsSafe
  966.             << " dead: " << lemDead
  967.               << ends;
  968.           ui.set_level(levelStr.str()); 
  969.           delete levelStr.str();
  970.         }
  971.  
  972.       // New level if enough lemmings are safe or too many are dead.
  973. //      if ((lemOut == SCENARIO_LEMMINGS_LEMMINGS && lemActive == 0) ||
  974. //          lemSafe >= SCENARIO_LEMMINGS_NEED)
  975.       if (lemDead > SCENARIO_LEMMINGS_LEMMINGS - SCENARIO_LEMMINGS_NEED
  976.           || lemSafe >= SCENARIO_LEMMINGS_NEED)
  977.         {
  978.           if (lemSafe < SCENARIO_LEMMINGS_NEED)
  979.         {
  980.           ostrstream msg;
  981.           msg << "YOU FAILED TO SAVE " << SCENARIO_LEMMINGS_NEED
  982.             << " LEMS.\nTry this level again." << ends;
  983.           locator.message_enq(msg.str());
  984.  
  985.           dontAdvance = True;
  986.         }
  987.  
  988.           newLevelTime = True;
  989.           newLevelTimer.set(NEW_LEVEL_TIME);
  990.         }          
  991.     }
  992.       else if (!newLevelTime && scenario == FIRE_DEMON 
  993.            && enemiesPlaying == 0)
  994.     {
  995.       newLevelTime = True;
  996.       newLevelTimer.set(NEW_LEVEL_TIME);
  997.     }
  998.     }
  999.  
  1000.  
  1001.   // LEVELS game style.
  1002.   if (!newLevelTime && style == UIsettings::LEVELS && 
  1003.       enemiesPlaying == 0)
  1004.     {
  1005.       newLevelTime = True;
  1006.       newLevelTimer.set(NEW_LEVEL_TIME);
  1007.     }
  1008.  
  1009.  
  1010.   // Call new_level() when newLevelTimer has expired.
  1011.   if (newLevelTime)
  1012.     {
  1013.       if (newLevelTimer.ready())
  1014.     {
  1015.       newLevelTime = False;
  1016.       new_level();
  1017.     }
  1018.       else
  1019.     newLevelTimer.clock();
  1020.     }
  1021. }
  1022.  
  1023.  
  1024.  
  1025. void Game::refill_check()
  1026. {
  1027.   if (refillTimer.ready())
  1028.     {
  1029.       if (!(style == UIsettings::SCENARIOS && scenario == BONUS))
  1030.     gameObjects.refill(&world,&locator);
  1031.       
  1032.       if (enemiesRefill &&
  1033.       (style == UIsettings::KILL || 
  1034.        style == UIsettings::DUEL
  1035.        || style == UIsettings::EXTENDED))
  1036.     refill_enemies();
  1037.       else if (style == UIsettings::SCENARIOS && scenario == HIVE)
  1038.     hive_refill_enemies();
  1039.       else if (style == UIsettings::SCENARIOS && scenario == FLAG)
  1040.     flag_refill_enemies();
  1041.       else if (style == UIsettings::SCENARIOS && scenario == LEMMINGS)
  1042.     lemmings_refill_enemies();
  1043.  
  1044.       refillTimer.set();
  1045.     }
  1046.   refillTimer.clock();
  1047. }
  1048.  
  1049.  
  1050.  
  1051. void Game::demo_check()
  1052. {
  1053.   if (demoOn)
  1054.     {
  1055.       if (!demoExtraTime && locator.enemies_alive() <= 1)
  1056.     {
  1057.       demoExtraTimer.set();
  1058.       demoExtraTime = True;
  1059.     }
  1060.       
  1061.       // Start new demo.
  1062.       if (demoCutoffTimer.ready() || 
  1063.       (demoExtraTime && demoExtraTimer.ready()))
  1064.     {
  1065.       demoCutoffTimer.set();
  1066.       demoExtraTime = False;
  1067.       locator.reset();
  1068.       ui.reset();
  1069.       demo_setup();
  1070.     }
  1071.       
  1072.       demoCutoffTimer.clock();
  1073.       demoExtraTimer.clock();
  1074.       world.clock();
  1075.       locator.clock();
  1076.     }        
  1077. }
  1078.  
  1079.  
  1080.  
  1081. PhysicalP Game::human_physical()
  1082. {
  1083.   PhysicalP obj;
  1084.   int which = -1;
  1085.   if (humanClass == A_None)
  1086.     which = Utils::choose(3);
  1087.  
  1088.   if (humanClass == A_Enforcer)
  1089.     {
  1090.       Pos pos = world.empty_rect(Enforcer::get_size_max());
  1091.       obj = new Enforcer(&world,&locator,pos);
  1092.     }
  1093.   else if (humanClass == A_Frog)
  1094.     {
  1095.       Id invalid;
  1096.       Pos pos = world.empty_rect(Frog::get_size_max());
  1097.       obj = new Frog(&world,&locator,pos,invalid);
  1098.     }
  1099.   else if (humanClass == A_Hero || which == 0)
  1100.     {
  1101.       Pos pos = world.empty_rect(Hero::get_size_max());
  1102.       obj = new Hero(&world,&locator,pos);
  1103.     }
  1104.   else if (humanClass == A_Ninja || which == 1)
  1105.     {
  1106.       Pos pos = world.empty_rect(Ninja::get_size_max());
  1107.       obj = new Ninja(&world,&locator,pos);
  1108.     }
  1109.   else if (humanClass == A_ChopperBoy || which == 2)
  1110.     {
  1111.       Pos pos = world.empty_rect(ChopperBoy::get_size_max());
  1112.       obj = new ChopperBoy(&world,&locator,pos);
  1113.     }
  1114.   else if (humanClass == A_Alien)
  1115.     {
  1116.       Pos pos = world.empty_rect(Alien::get_size_max());
  1117.       obj = new Alien(&world,&locator,pos);
  1118.     }
  1119.   else if (humanClass == A_FireDemon)
  1120.     {
  1121.       Pos pos = world.empty_rect(FireDemon::get_size_max());
  1122.       obj = new FireDemon(&world,&locator,pos);
  1123.     }
  1124.   else
  1125.     assert(0);
  1126.  
  1127.  
  1128.   assert(obj);
  1129.   return obj;
  1130. }
  1131.  
  1132.  
  1133.  
  1134. // The default set of classes to be used by enemy_physical.
  1135. ClassId Game::defaultChoosable[DEFAULT_CHOOSABLE_NUM] =
  1136. { A_Ninja,A_Hero,A_ChopperBoy,A_Enforcer,A_Alien,A_FireDemon};
  1137.  
  1138. int Game::defaultChoosableWeights[DEFAULT_CHOOSABLE_NUM] =
  1139. { 3,      3,     2,           1,         1,     0};
  1140.  
  1141.  
  1142. PhysicalP Game::enemy_physical(ClassId *choosable,int choosableNum)
  1143. {
  1144.   int localWeights[DEFAULT_CHOOSABLE_NUM];
  1145.   int *weights;
  1146.  
  1147.   if (choosableNum == 0) // Use defaults
  1148.     {
  1149.       choosable = defaultChoosable;
  1150.       choosableNum = DEFAULT_CHOOSABLE_NUM;
  1151.       weights = defaultChoosableWeights;
  1152.     }
  1153.   else
  1154.     {
  1155.       assert(choosable);
  1156.       weights = localWeights;
  1157.       // Get weights from defaultChoosableWeights.
  1158.       for (int n = 0; n < choosableNum; n++)
  1159.     for (int m = 0; m < DEFAULT_CHOOSABLE_NUM; m++)
  1160.       if (choosable[n] == defaultChoosable[m])
  1161.         weights[n] = defaultChoosableWeights[m];
  1162.     }
  1163.  
  1164.   int weightsSum = 0;
  1165.   for (int n = 0; n < choosableNum; n++)
  1166.     weightsSum += weights[n];
  1167.   
  1168.   int choice = Utils::choose(weightsSum);
  1169.   int weightBelow = 0;
  1170.   for (n = 0; n < choosableNum; n++)
  1171.     {
  1172.       weightBelow += weights[n];
  1173.       if (choice < weightBelow)
  1174.     return enemy_physical(choosable[n]);
  1175.     }
  1176.   assert(0);
  1177.   return NULL;
  1178. }
  1179.  
  1180.  
  1181.  
  1182. PhysicalP Game::enemy_physical(ClassId classId)
  1183. {
  1184.   assert(classId == A_Ninja || classId == A_Hero 
  1185.      || classId == A_ChopperBoy || classId == A_Enforcer 
  1186.      || classId == A_Alien || classId == A_Frog 
  1187.      || classId == A_FireDemon);
  1188.  
  1189.   PhysicalP obj;
  1190.   switch (classId) {
  1191.   case A_Ninja:
  1192.     {
  1193.       Pos pos = world.empty_rect(Ninja::get_size_max());
  1194.       obj = new Ninja(&world,&locator,pos);
  1195.     }
  1196.     break;
  1197.   case A_Hero:
  1198.     {
  1199.       Pos pos = world.empty_rect(Hero::get_size_max());
  1200.       obj = new Hero(&world,&locator,pos);
  1201.     }
  1202.     break;
  1203.   case A_ChopperBoy:
  1204.     {
  1205.       Pos pos = world.empty_rect(ChopperBoy::get_size_max());
  1206.       obj = new ChopperBoy(&world,&locator,pos);
  1207.     }
  1208.     break;
  1209.   case A_Enforcer:
  1210.     {
  1211.       Pos pos = world.empty_rect(Enforcer::get_size_max());
  1212.       obj = new Enforcer(&world,&locator,pos);
  1213.     }
  1214.     break;
  1215.   case A_Alien:
  1216.     {
  1217.       Pos pos = world.empty_rect(Alien::get_size_max());
  1218.       obj = new Alien(&world,&locator,pos);
  1219.     }
  1220.     break;
  1221.   case A_Frog:
  1222.     {
  1223.       Id invalid;
  1224.       Pos pos = world.empty_rect(Frog::get_size_max());
  1225.       obj = new Frog(&world,&locator,pos,invalid);
  1226.     }
  1227.     break;
  1228.   case A_FireDemon:
  1229.     {
  1230.       Pos pos = world.empty_rect(FireDemon::get_size_max());
  1231.       obj = new FireDemon(&world,&locator,pos);
  1232.     }
  1233.     break;
  1234.   default:
  1235.     assert(0);
  1236.   }
  1237.  
  1238.   assert(obj);
  1239.   return obj;
  1240. }
  1241.  
  1242.  
  1243.  
  1244. Game::Scenario Game::choose_scenario()
  1245. {
  1246.   if (scenarioOverride != HIGHEST)
  1247.     return scenarioOverride;
  1248.   else
  1249.     return (Scenario)Utils::choose(HIGHEST);
  1250. }
  1251.  
  1252.  
  1253.  
  1254. void Game::end_game()
  1255. {
  1256.   gameOn = False;
  1257.  
  1258.   ostrstream winners;
  1259.   winners << "Game Over.  Winners: ";
  1260.   int winnersNum = 0;
  1261.   for (int n = 0; n < humansNum; n++)
  1262.     {
  1263.       HumanP human = locator.get_human(n);
  1264.  
  1265.       if (human->alive() || human->get_lives() == IT_INFINITE_LIVES 
  1266.       || human->get_lives() > 0)
  1267.     {
  1268.       winners << human->get_name() << "(" << human->get_human_kills() 
  1269.         << " human(s), " << human->get_enemy_kills() << " machine(s)) ";
  1270.       winnersNum++;
  1271.     }
  1272.     }
  1273.   if (winnersNum)
  1274.     {
  1275.       winners << ends;
  1276.       locator.message_enq(winners.str());
  1277.     }
  1278.   else if (locator.enemies_alive())
  1279.     {
  1280.       ostrstream str;
  1281.       if (humansNum)
  1282.     str << "Ha, ha.  You puny fleshlings can never defeat your " <<
  1283.       "computer masters." << ends;
  1284.       else
  1285.     str << "The game is over." << ends;
  1286.       locator.message_enq(str.str());
  1287.     }
  1288.   else
  1289.     {
  1290.       ostrstream str;
  1291.       if (polCorrect)
  1292.     str << "Game Over.  Everybody is dead.  You all suck." << ends;
  1293.       else
  1294.     str << "Game Over.  Everybody is dead." << ends;
  1295.       locator.message_enq(str.str());
  1296.     }
  1297.   
  1298.   otherInputReset.set();
  1299. }
  1300.  
  1301.  
  1302.  
  1303. void Game::new_level(Boolean fromReset)
  1304. {
  1305.   // dontAdvance should only be used for SCENARIOS game style.
  1306.   assert(!dontAdvance || style == UIsettings::SCENARIOS);
  1307.  
  1308.   if (!dontAdvance)
  1309.     level++;
  1310.  
  1311.   if (level > levelHighest)
  1312.     levelHighest = level;
  1313.  
  1314.   ostrstream lStr;       // For level box on the side of the Ui.
  1315.   ostrstream lTitleStr;  // For Ui title screen.
  1316.  
  1317.   // Switch on the current game style.
  1318.   switch(style) {
  1319.   case UIsettings::SCENARIOS:
  1320.     {
  1321.       if (!dontAdvance)
  1322.     scenario = choose_scenario();
  1323.       else
  1324.     dontAdvance = False;
  1325.  
  1326.       // Switch on the possible scenarios.
  1327.       switch(scenario) {
  1328.       case EXTERMINATE:
  1329.     world.set_rooms_next(worldRooms);
  1330.     break;
  1331.       case BONUS:
  1332.     {
  1333.       Rooms rooms(2,1);
  1334.       world.set_rooms_next(rooms);
  1335.     }
  1336.     break;
  1337.       case HIVE:
  1338.     {
  1339.       Rooms rooms(5,5);
  1340.       world.set_rooms_next(rooms);
  1341.     }
  1342.     break;
  1343.       case FLAG:
  1344.     {
  1345.       Rooms rooms(3,6);
  1346.       world.set_rooms_next(rooms);
  1347.     }
  1348.     break;
  1349.       case LEMMINGS:
  1350.     {
  1351.       Rooms rooms(1,4);
  1352.       world.set_rooms_next(rooms);
  1353.     }
  1354.     break;
  1355.       case FIRE_DEMON:
  1356.     {
  1357.       Rooms rooms(2,2);
  1358.       world.set_rooms_next(rooms);
  1359.     }
  1360.     break;
  1361.       default:
  1362.     assert(0);
  1363.     break;
  1364.       };
  1365.  
  1366.       world.reset();
  1367.       
  1368.  
  1369.       // Clean up all Physicals in the Game.  World must be reset so 
  1370.       // that human players can be moved to the inside of the world.
  1371.       PhysicalIter pIter(locator);
  1372.       PhysicalP p;
  1373.       while (p = pIter())
  1374.     {
  1375.       IntelP intel = p->get_intel();
  1376.       Boolean saveMe = False;
  1377.  
  1378.       // Save Human controlled physicals.
  1379.       if (intel && intel->is_human())
  1380.         saveMe = True;
  1381.  
  1382.       // Save Machines that are slaves of Humans.
  1383.       if (intel && !intel->is_human())
  1384.         {
  1385.           IntelP master = 
  1386.         locator.lookup(((MachineP)intel)->get_master_intel_id());
  1387.           if (master && master->is_human())
  1388.         saveMe = True;
  1389.         }
  1390.  
  1391.       // Move to a new location inside the World.
  1392.       if (saveMe)
  1393.         {
  1394.           assert(p->is_moving());
  1395.           const Area &area = p->get_area();
  1396.           Size size;
  1397.           Pos pos;
  1398.           area.get_rect(pos,size);
  1399.           ((MovingP)p)->relocate(world.empty_rect(size));
  1400.         }
  1401.       // Kill Items not held by Human players.
  1402.       else if (p->is_item())
  1403.         {
  1404.           Id holderId = ((ItemP)p)->get_holder_id();
  1405.           PhysicalP holder = locator.lookup(holderId);
  1406.           if (!(holder && (intel = holder->get_intel())
  1407.             && intel->is_human()))
  1408.         off_clock_kill(p);
  1409.         }
  1410.       // Quietly kill everything else, ha, ha, ha.
  1411.       else
  1412.         off_clock_kill(p);
  1413.     }
  1414.  
  1415.       // Switch on the possible scenarios.
  1416.       switch(scenario) {
  1417.       case EXTERMINATE:
  1418.     {
  1419.       lTitleStr << "[" << level << "] EXTERMINATE" << ends;
  1420.       lStr << "[" << level << "] EXTERMINATE\nKill all machines." << ends;
  1421.       enemiesNum += LEVEL_ENEMIES_INCR;
  1422.       for (int m = 0; m < enemiesNum; m++)
  1423.         create_enemy();
  1424.     }
  1425.     break;
  1426.       case BONUS:
  1427.     {
  1428.       for (int n = 0; n < SCENARIO_BONUS_FROGS; n++)
  1429.         {
  1430.           PhysicalP p = create_enemy(enemy_physical(A_Frog));
  1431.           frogs[n] = p->get_id();
  1432.         }
  1433.       frogsRemaining = SCENARIO_BONUS_FROGS;
  1434.       newLevelTimer.set(SCENARIO_BONUS_TIME);
  1435.       newLevelTime = True;
  1436.       lTitleStr << "[" << level << "] BONUS LEVEL" << ends;
  1437.       lStr << "[" << level << "] BONUS LEVEL\nfrogs remaining: " 
  1438.         << SCENARIO_BONUS_FROGS << ends;
  1439.     }
  1440.     break;
  1441.       case HIVE:
  1442.     {
  1443.       // Aliens are created in Game::clock.
  1444.       lTitleStr << "[" << level << "] HIVE" << ends;
  1445.       lStr << "[" << level << "] HIVE.\nFind the exit." << ends;
  1446.       
  1447.       // Create the Xit.
  1448.       Pos pos = world.empty_accessible_rect(Xit::get_size_max());
  1449.       PhysicalP p = new Xit(&world,&locator,pos);
  1450.       assert(p);
  1451.       locator.add(p);
  1452.       xitId = p->get_id();
  1453.     }
  1454.     break;
  1455.       case FLAG:
  1456.     {
  1457.       for (int n = 0; n < SCENARIO_FLAG_FLAGS; n++)
  1458.         {
  1459.           Pos pos = world.empty_accessible_rect(Flag::get_size_max());
  1460.           PhysicalP p = new Flag(&world,&locator,pos);
  1461.           assert(p);
  1462.           locator.add(p);
  1463.           flagIds[n] = p->get_id();
  1464.         }
  1465.       flagsRemaining = SCENARIO_FLAG_FLAGS;
  1466.       lTitleStr << "[" << level << "] CAPTURE THE FLAG" << ends;
  1467.       lStr << "[" << level << "] COLLECT " << SCENARIO_FLAG_FLAGS 
  1468.         << " FLAGS.\nremaining: " << SCENARIO_FLAG_FLAGS << ends;
  1469.     }
  1470.     break;
  1471.       case LEMMINGS:
  1472.     {
  1473.       // Know these area is open because they are within the 
  1474.       // (OBJECT_COL_MAX,OBJECT_ROW_MAX) margain around the World edge.
  1475.       Size worldSize = world.get_size();
  1476.       Size homeSize = Home::get_size();
  1477.       Pos homePos(worldSize.width - 12 * WSQUARE_WIDTH - homeSize.width,
  1478.               worldSize.height - WSQUARE_HEIGHT - homeSize.height);
  1479.       PhysicalP home = 
  1480.         new Home(&world,&locator,homePos);
  1481.       assert(home);
  1482.       locator.add(home);
  1483.       homeId = home->get_id();
  1484.       
  1485.  
  1486.       // Create Trapdoor after Home because it needs homeId.
  1487.       Pos trapdoorPos(3*WSQUARE_WIDTH,WSQUARE_HEIGHT);
  1488.       PhysicalP trapdoor = 
  1489.         new Trapdoor(&world,&locator,trapdoorPos,homeId);
  1490.       locator.add(trapdoor);
  1491.       trapdoorId = trapdoor->get_id();
  1492.       
  1493.       lemmingsSafe = lemmingsOut = lemmingsActive = 0;
  1494.       lTitleStr << "[" << level << "] LEMS" << ends;
  1495.       lStr << "[" << level << "] SAVE " 
  1496.         << SCENARIO_LEMMINGS_NEED << " LEMS\n" 
  1497.           << "out: 0 safe: 0 dead: 0" << ends;
  1498.     }
  1499.     break;
  1500.       case FIRE_DEMON:
  1501.     {
  1502.       lTitleStr << "[" << level << "] FIRE DEMON" << ends;
  1503.       lStr << "[" << level << "] Kill the Fire Demon." << ends;
  1504.       create_enemy(enemy_physical(A_FireDemon));
  1505.     }
  1506.     break;
  1507.       default:
  1508.     assert(0);
  1509.     break;
  1510.       };
  1511.     }
  1512.     break;
  1513.     
  1514.   case UIsettings::LEVELS:
  1515.     {
  1516.       // World stays the same size.
  1517.       if (!fromReset)
  1518.     world.reset();
  1519.       lTitleStr << "Level: " << level << ends;
  1520.       lStr << "Level: " << level << ends;
  1521.       enemiesNum += LEVEL_ENEMIES_INCR;
  1522.       for (int m = 0; m < enemiesNum; m++)
  1523.     create_enemy();
  1524.     }
  1525.     break;
  1526.  
  1527.   case UIsettings::KILL:
  1528.   case UIsettings::DUEL:
  1529.   case UIsettings::EXTENDED:
  1530.   case UIsettings::TRAINING:
  1531.     {
  1532.       // World stays the same size.
  1533.       if (!fromReset)
  1534.     world.reset();
  1535.       lTitleStr << "Level: " << level << ends;
  1536.       lStr << "Level: " << level << ends;
  1537.       newLevelTimer.set(LEVEL_TIME);
  1538.       newLevelTime = True;
  1539.  
  1540.       // NOTE: Do not kill off extra Physical objects for these styles.
  1541.     }
  1542.     break;
  1543.   };
  1544.   
  1545.   gameObjects.level_reset(world.get_dim());
  1546.  
  1547.   // No gameObjects for BONUS scenario.
  1548.   if (!(style == UIsettings::SCENARIOS && scenario == BONUS))
  1549.     gameObjects.refill(&world,&locator);
  1550.  
  1551.   ui.set_level_title(lTitleStr.str());
  1552.   ui.set_level(lStr.str());
  1553.   delete lTitleStr.str();
  1554.   delete lStr.str();
  1555.  
  1556.   levelTitleTime = True;
  1557.   levelTitleTimer.set();
  1558. }
  1559.  
  1560.  
  1561.  
  1562. void Game::reset()
  1563. {
  1564.   demoOn = False;
  1565.   locator.set_messages_ignore(False);
  1566.   if (gameOn)
  1567.     end_game();
  1568.  
  1569.   extraTime = False;
  1570.   levelTitleTime = False;
  1571.   newLevelTime = False;
  1572.   enemyNameCount = 0;
  1573.   enemiesRefill = enemiesRefillNext;
  1574.   humansNum = humansNumNext;
  1575.   enemiesNum = enemiesNumNext;
  1576.   style = styleNext;
  1577.   level = 0; // So will start out at 1.
  1578.   levelHighest = 0;
  1579.  
  1580.   locator.reset();
  1581.   ui.reset();
  1582.  
  1583.   if (style != UIsettings::SCENARIOS)
  1584.     {
  1585.       world.set_rooms_next(worldRooms);
  1586.       world.reset();
  1587.     }
  1588.   // else the world is reset in new_level().
  1589.   
  1590.   if (!polCorrect)
  1591.     {
  1592.       ostrstream msg;
  1593.       msg << wittySayings[Utils::choose(WITTY_SAYINGS_NUM)] << ends;
  1594.       locator.message_enq(msg.str());
  1595.     }
  1596.  
  1597.   /* Don't need to call Ui::set_* because the new values originally came 
  1598.      from Ui. */
  1599.  
  1600.   gameObjects.game_reset(oneItem,noItems,oneEach);
  1601.   style_reset();
  1602.   new_level(True);
  1603.   humans_reset(); // After new_level because world must be reset.
  1604.  
  1605.   gameOn = True;
  1606.  
  1607.   // Force Game::clock to set Ui::set_intels_playing().
  1608.   humansPlayingPrev = enemiesPlayingPrev = -1;  // Used to be 0.
  1609. }
  1610.  
  1611.  
  1612.  
  1613. void Game::process_x_resources(int *,char **)
  1614. {
  1615.   for (int dpyNum = 0; dpyNum < ui.get_dpy_max(); dpyNum++)
  1616.     if (!ui.keyset_set(dpyNum))
  1617.       {
  1618.     const char * const *keysNames = ui.get_keys_names();
  1619.     
  1620.     KeySym right[UI_KEYS_MAX][2],left[UI_KEYS_MAX][2];
  1621.     
  1622.     for (int n = 0; n < UI_KEYS_MAX; n++)
  1623.       for (int which = 0; which < 2; which++)
  1624.         {
  1625.           { // Right keys.
  1626.         right[n][which] = 0;
  1627.         
  1628.         ostrstream strm;
  1629.         if (which == 0)
  1630.           strm << "right_" << keysNames[n] << ends;
  1631.         else
  1632.           strm << "right_" << keysNames[n] << "_2" << ends;
  1633.         char *option = strm.str();
  1634.         
  1635.         // Should we free value??
  1636.         char *value = XGetDefault(ui.get_dpy(0),XEVIL_CLASS,option);
  1637.         if (value)
  1638.           {
  1639.             KeySym keysym = XStringToKeysym(value);
  1640.             if (keysym != NoSymbol)
  1641.               right[n][which] = keysym;
  1642.           }
  1643.         delete option;
  1644.           }
  1645.           
  1646.           { // Left Keys.
  1647.         left[n][which] = 0;
  1648.         
  1649.         ostrstream strm;
  1650.         if (which == 0)
  1651.           strm << "left_" << keysNames[n] << ends;
  1652.         else
  1653.           strm << "left_" << keysNames[n] << "_2" << ends;
  1654.         char *option = strm.str();
  1655.         
  1656.         // Should we free value??
  1657.         char *value = XGetDefault(ui.get_dpy(0),XEVIL_CLASS,option);
  1658.         if (value)
  1659.           {
  1660.             KeySym keysym = XStringToKeysym(value);
  1661.             if (keysym != NoSymbol)
  1662.               left[n][which] = keysym;
  1663.           }
  1664.         delete option;
  1665.           }
  1666.         }
  1667.     ui.set_keyset(dpyNum,KEYSET_DEFAULT,right,left);
  1668.       }
  1669. }
  1670.  
  1671.  
  1672.  
  1673. void Game::parse_args(int *argc,char **argv)
  1674. {
  1675.   for (int n = 0; n < *argc; n++)
  1676.     {
  1677.       if (! strcmp("-duel",argv[n]))
  1678.     {
  1679.       style = styleNext = UIsettings::DUEL;
  1680.       ui.set_style(style);
  1681.     }
  1682.       else if (! strcmp("-extended",argv[n]))
  1683.     {
  1684.       style = styleNext = UIsettings::EXTENDED;
  1685.       ui.set_style(style);
  1686.     }
  1687.       else if ((! strcmp("-h",argv[n])) || (! strcmp("-help",argv[n])))
  1688.     {
  1689.       cout 
  1690.         << "usage: " << argv[0] 
  1691.         << " [-display display_name] [-d<x> display_name | "
  1692.         << "-display<x> display_name] "
  1693.         << "[-duel] [-extended] [-h | -help] [-humans number] [-info] "
  1694.         << "[-kill] "
  1695.         << "[-keys alpha | decmips | iris | mac | ncd | rsaix | sun3 | sun4 "
  1696.         << "| sun4_sparc | tektronix] [-levels] [-machines number] [-map] "
  1697.         << "[-pc] [-regenerate_machines] [-rooms acrossxdown] "
  1698.         << "[-speed time-in-ms] [-synchronous] [-training]" << endl;
  1699.       exit(0);
  1700.     }
  1701.       else if (! strcmp("-harmless",argv[n]))
  1702.     intelHarmless = True;
  1703.       else if (!strcmp("-human_class",argv[n]) && (n + 1 < *argc))
  1704.     {
  1705.       assert(humanClass == A_None);
  1706.       n++;
  1707.       if (!strcmp("enforcer",argv[n]))
  1708.         humanClass = A_Enforcer;
  1709.       else if (!strcmp("frog",argv[n]))
  1710.         humanClass = A_Frog;
  1711.       else if (!strcmp("hero",argv[n]))
  1712.         humanClass = A_Hero;
  1713.       else if (!strcmp("ninja",argv[n]))
  1714.         humanClass = A_Ninja;
  1715.       else if (!strcmp("chopper-boy",argv[n]))
  1716.         humanClass = A_ChopperBoy;
  1717.       else if (!strcmp("alien",argv[n]))
  1718.         humanClass = A_Alien;
  1719.       else if (!strcmp("fire-demon",argv[n]))
  1720.         humanClass = A_FireDemon;
  1721.     }
  1722.       else if ((! strcmp("-humans",argv[n])) && (n + 1 < *argc))
  1723.     {
  1724.       humansNumNext = atoi(argv[n+1]);
  1725.       humansNumNext = min(humansNumNext,Locator::HUMANS_MAX);
  1726.       ui.set_humans_num(humansNumNext);
  1727.       n++;
  1728.     }
  1729.       else if (! strcmp("-info",argv[n]))
  1730.     {
  1731.       cout << 
  1732.       "   Copyright (C) 1994,1995  Steve Hardt " << endl << 
  1733.       endl << 
  1734.       "    This program is free software; you can redistribute it and/or modify" << endl <<
  1735.       "    it under the terms of the GNU General Public License as published by" << endl <<
  1736.       "    the Free Software Foundation; either version 1, or (at your option)" << endl <<
  1737.       "    any later version." << endl <<
  1738.       endl <<
  1739.       "    This program is distributed in the hope that it will be useful," << endl <<
  1740.       "    but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl <<
  1741.       "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the" << endl << 
  1742.       "    GNU General Public License for more details." << endl <<
  1743.       endl <<
  1744.       "    You should have received a copy of the GNU General Public License" << endl <<
  1745.       "    along with this program; if not, write to the Free Software" << endl <<
  1746.       "    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA." << endl <<
  1747.       endl <<
  1748.       "    Design and programming:" << endl <<
  1749.       "    Steve Hardt" << endl << 
  1750.           "    hardts@theory.lcs.mit.edu" << endl <<
  1751.           "    hardts@athena.mit.edu" << endl <<
  1752.       "    hardts@media.mit.edu" << 
  1753.       "    hardts@blake.3dem.bioch.bcm.tmc.edu" << endl <<
  1754.       "    2043 McClendon" << endl <<
  1755.       "    Houston, TX 77030" << endl << 
  1756.       endl <<
  1757.       "    The XEvil distribution is available via anonymous ftp at" << endl <<
  1758.       "    ftp.x.org under /contrib/games." << endl <<
  1759.       "    http://theory.lcs.mit.edu/~hardts/xevil.html" << endl;
  1760.       exit(0);
  1761.     }
  1762.       else if (! strcmp("-kill",argv[n]))
  1763.     {
  1764.       style = styleNext = UIsettings::KILL;
  1765.       ui.set_style(style);
  1766.     }
  1767.       else if ((! strcmp("-keys",argv[n])) && (n + 1 < *argc))
  1768.     {
  1769.       // Sets the keyset for all displays to the same value.
  1770.       n++;
  1771.       for (int dpyNum = 0; dpyNum < ui.get_dpy_max(); dpyNum++)
  1772.         {
  1773.           if (! strcmp("alpha",argv[n]))
  1774.         ui.set_keyset(dpyNum,UIalpha);
  1775.           if (! strcmp("decmips",argv[n]))
  1776.         ui.set_keyset(dpyNum,UIdecmips);
  1777.           if (! strcmp("iris",argv[n]))
  1778.         ui.set_keyset(dpyNum,UIiris);
  1779.           if (! strcmp("mac",argv[n]))
  1780.         ui.set_keyset(dpyNum,UImac);
  1781.           if (! strcmp("ncd",argv[n]))
  1782.         ui.set_keyset(dpyNum,UIncd);
  1783.           if (! strcmp("rsaix",argv[n]))
  1784.         ui.set_keyset(dpyNum,UIrsaix);
  1785.           if (! strcmp("sun3",argv[n]))
  1786.         ui.set_keyset(dpyNum,UIsun3);
  1787.           if (! strcmp("sun4",argv[n]))
  1788.         ui.set_keyset(dpyNum,UIsun4);
  1789.           if (! strcmp("sun4_sparc",argv[n]))
  1790.         ui.set_keyset(dpyNum,UIsun4_sparc);
  1791.           if (! strcmp("tektronix",argv[n]))
  1792.         ui.set_keyset(dpyNum,UItektronix);
  1793.         }
  1794.     }
  1795.       else if (!strcmp("-levels",argv[n]))
  1796.     {
  1797.       style = styleNext = UIsettings::LEVELS;
  1798.       ui.set_style(style);
  1799.     }
  1800.       else if ((! strcmp("-machines",argv[n])) && (n + 1 < *argc))
  1801.     {
  1802.       enemiesNumNext = atoi(argv[n+1]);
  1803.       enemiesNumNext = min(enemiesNumNext,Locator::ENEMIES_MAX);
  1804.       ui.set_enemies_num(enemiesNumNext);
  1805.       n++;
  1806.     }
  1807.       else if (! strcmp("-map",argv[n]))
  1808.     world.set_map_print(True);
  1809.       else if (! strcmp("-no_items",argv[n]))
  1810.     noItems = True;
  1811.       else if (! strcmp("-one_each",argv[n]))
  1812.     oneEach = True;
  1813.       else if ((! strcmp("-one_item",argv[n])) && (n + 1 < *argc))
  1814.     {
  1815.       n++;
  1816.       oneItem = argv[n];
  1817.     }
  1818.       /* "-pc" command line option handled by Game::is_pol_correct. */
  1819.       else if (! strcmp("-regenerate_machines",argv[n]))
  1820.     {
  1821.       enemiesRefillNext = True;
  1822.       ui.set_enemies_refill(True);
  1823.     }
  1824.       else if (! strcmp("-rooms",argv[n]) && (n + 1 < *argc))
  1825.     {
  1826.       Rooms temp;
  1827.       if (sscanf(argv[n+1],"%dx%d",
  1828.              &temp.acrossMax,&temp.downMax) == 2)
  1829.         worldRooms = temp;
  1830.       n++;
  1831.     }
  1832.       else if ((! strcmp("-scenario",argv[n])) && (n + 1 < *argc))
  1833.     {
  1834.       n++;
  1835.       if (!(strcmp("exterminate",argv[n])))
  1836.         scenarioOverride = EXTERMINATE;
  1837.       else if (!(strcmp("flag",argv[n])))
  1838.         scenarioOverride = FLAG;
  1839.       else if (!(strcmp("bonus",argv[n])))
  1840.         scenarioOverride = BONUS;
  1841.       else if (!(strcmp("hive",argv[n])))
  1842.         scenarioOverride = HIVE;
  1843.       else if (!(strcmp("lems",argv[n])))
  1844.         scenarioOverride = LEMMINGS;
  1845.       else if (!(strcmp("fire-demon",argv[n])))
  1846.         scenarioOverride = FIRE_DEMON;
  1847.     }
  1848.       else if (!strcmp("-scenarios",argv[n]))
  1849.     {
  1850.       style = styleNext = UIsettings::SCENARIOS;
  1851.       ui.set_style(style);
  1852.     }
  1853.       else if ((! strcmp("-speed",argv[n])) && (n + 1 < *argc))
  1854.     {
  1855.       quanta = atoi(argv[n+1]);
  1856.       ui.set_quanta(quanta);
  1857.       n++;
  1858.     }
  1859.       else if (! strcmp("-stats",argv[n]))
  1860.     showStats = True;
  1861.       else if (! strcmp("-synchronous",argv[n]))
  1862.     for (int m = 0; m < ui.get_dpy_max(); m++)
  1863.       XSynchronize(ui.get_dpy(m),True);
  1864.       else if (! strcmp("-training",argv[n]))
  1865.     {
  1866.       style = styleNext = UIsettings::TRAINING;
  1867.       ui.set_style(style);
  1868.     }
  1869.     }
  1870. }
  1871.  
  1872.  
  1873.  
  1874. Boolean Game::is_pol_correct(int *argc,char **argv)
  1875. {
  1876.   for (int n = 0; n < *argc; n++)
  1877.     if (! strcmp("-pc",argv[n]))
  1878.       return True;
  1879.  
  1880.   return False;
  1881. }
  1882.  
  1883.  
  1884.  
  1885. char **Game::display_names(int *argc,char **argv)
  1886. {
  1887.   ostrstream dashDisplay[UI_VIEWPORTS_MAX][2];
  1888.   typedef char *charP;
  1889.   char **displayNames = new charP [UI_VIEWPORTS_MAX];
  1890.  
  1891.   for (int n = 0; n < UI_VIEWPORTS_MAX; n++)
  1892.     {
  1893.       displayNames[n] = new char [Xvars::DISPLAY_NAME_LENGTH];
  1894.       strcpy(displayNames[n],"");
  1895.       dashDisplay[n][0] << "-display" << n << ends;
  1896.       dashDisplay[n][1] << "-d" << n << ends;
  1897.     }
  1898.  
  1899.   // Loop through all command line arguments.
  1900.   for (n = 0; n < *argc - 1 ; n++)
  1901.     {
  1902.       // Set display name for all viewports.
  1903.       if (!strcmp(argv[n],"-display") || !strcmp(argv[n],"-d"))
  1904.     {
  1905.       assert(strlen(argv[n+1]) < Xvars::DISPLAY_NAME_LENGTH);
  1906.       for (int vNum = 0; vNum < UI_VIEWPORTS_MAX; vNum++)
  1907.         strcpy(displayNames[vNum],argv[n+1]);
  1908.     }
  1909.       
  1910.       // Set display name for one viewport.
  1911.       for (int m = 0; m < UI_VIEWPORTS_MAX; m++)
  1912.     for (int which = 0; which < 2; which++)
  1913.       if (!strcmp(argv[n],dashDisplay[m][which].str()))
  1914.         {
  1915.           assert(strlen(argv[n+1]) < Xvars::DISPLAY_NAME_LENGTH);
  1916.           strcpy(displayNames[m],argv[n+1]);
  1917.         }
  1918.     }
  1919.  
  1920.   for (n = 0; n < UI_VIEWPORTS_MAX; n++)
  1921.     for (int which = 0; which < 2; which++)
  1922.       delete dashDisplay[n][which].str();
  1923.  
  1924.   return displayNames;
  1925. }
  1926.  
  1927.  
  1928.  
  1929. void Game::humans_reset()
  1930. {
  1931.   assert(humansNum <= Xvars::HUMAN_COLORS_NUM);
  1932.   assert(humansNum <= Locator::HUMANS_MAX);
  1933.  
  1934.   // Doesn't really have to be done if polCorrect.
  1935.   assert(humansNum <= INTEL_NAMES_NUM);
  1936.   int intelNamesIndices[INTEL_NAMES_NUM];
  1937.   Utils::randomList(intelNamesIndices,INTEL_NAMES_NUM);
  1938.  
  1939.  
  1940.   // Create humans along with their viewports, if necessary.
  1941.   for (int vn = 0; vn < humansNum; vn++)
  1942.     {
  1943.       assert(vn <= ui.get_viewports_num());
  1944.       if (vn == ui.get_viewports_num())
  1945.     {
  1946.       int vNum = ui.add_viewport();
  1947.       assert(vn == vNum);
  1948.       int v = ui.get_viewports_num_on_dpy(ui.get_dpy_num(vNum));
  1949.       if (v == 1)
  1950.         ui.set_input(vNum,UI_KEYS_RIGHT);
  1951.       else if (v == 2)
  1952.         ui.set_input(vNum,UI_KEYS_LEFT);
  1953.     }
  1954.       ostrstream namePc;
  1955.       if (polCorrect)
  1956.     namePc << "Human-" << vn << ends;
  1957.  
  1958.       // Give infinite lives for UIsettings::EXTENDED.
  1959.       // Not infinite lives for Uisettings::DUEL.
  1960.       int lives = (style == UIsettings::EXTENDED) ? IT_INFINITE_LIVES : 
  1961.       (style == UIsettings::SCENARIOS ? HUMAN_LIVES_SCENARIOS :
  1962.        HUMAN_LIVES);
  1963.  
  1964.       HumanP human = 
  1965.     new Human(&world,&locator,
  1966.           (polCorrect?namePc.str():intelNames[intelNamesIndices[vn]]),
  1967.           lives,vn);
  1968.       
  1969.       assert(human);
  1970.       if (polCorrect)
  1971.     delete namePc.str();
  1972.  
  1973.       locator.register_human(human);
  1974.       ui.register_intel(vn,human);
  1975.  
  1976.       // Actual objects for humans.
  1977.       PhysicalP obj= human_physical();
  1978.       locator.add(obj);
  1979.       obj->set_intel(human);
  1980.     }
  1981.  
  1982.   int delNum = ui.get_viewports_num() - humansNum;
  1983.   for (int n = 0; n < delNum; n++)
  1984.     if (ui.get_viewports_num() > 1)
  1985.       ui.del_viewport();
  1986. }
  1987.  
  1988.  
  1989.  
  1990. void Game::style_reset()
  1991. {
  1992.   // So first level will start out with LEVEL_ENEMIES_INITIAL.
  1993.   if (style == UIsettings::SCENARIOS || style == UIsettings::LEVELS)
  1994.     enemiesNum = LEVEL_ENEMIES_INITIAL - LEVEL_ENEMIES_INCR;
  1995.     
  1996.   if (style == UIsettings::KILL || style == UIsettings::DUEL 
  1997.        || style == UIsettings::EXTENDED)
  1998.     for (int m = 0; m < enemiesNum; m++)
  1999.       create_enemy();
  2000.  
  2001.   
  2002.   if ((style == UIsettings::DUEL || style == UIsettings::EXTENDED) 
  2003.       && humansNum < 2)
  2004.     {
  2005.       ostrstream str;
  2006.       str << "!!!!!!!! YOU NEED AT LEAST 2 HUMAN PLAYERS FOR A "
  2007.       << "DUEL !!!!!!!!" << ends;
  2008.       locator.message_enq(str.str());
  2009.     }
  2010. }
  2011.  
  2012.  
  2013.  
  2014. void Game::intro()
  2015. {
  2016.   ostrstream msg;
  2017.   msg << "XEvil version " << VERSION 
  2018.     << ", Copyright (C) 1994,1995 Steve Hardt (hardts@theory.lcs.mit.edu)" 
  2019.       << "\n" << "http://theory.lcs.mit.edu/~hardts/xevil.html" << ends;
  2020.   locator.message_enq(msg.str());
  2021.   
  2022.   cout << "XEvil version " << VERSION << 
  2023.     ", Copyright (C) 1994,1995 Steve Hardt" << endl <<
  2024.           "hardts@theory.lcs.mit.edu" << endl <<
  2025.           "hardts@athena.mit.edu" << endl <<
  2026.       "hardts@media.mit.edu" << endl << 
  2027.       "hardts@blake.3dem.bioch.bcm.tmc.edu" << endl;
  2028.   cout << "XEvil comes with ABSOLUTELY NO WARRANTY." << endl;
  2029.   
  2030.   cout << "Type 'xevil -info' for information on redistribution and " 
  2031.     << "on NO WARRANTY." << endl;
  2032.   cout << "The XEvil distribution can be found at ftp.x.org under /contrib/games." << endl;
  2033.   cout << "http://theory.lcs.mit.edu/~hardts/xevil.html" << endl;
  2034. }
  2035.  
  2036.  
  2037.  
  2038. void Game::print_stats()
  2039. {
  2040.   const Stats &shot = Shot::get_stats();
  2041.   const Stats &grenade = Grenade::get_stats();
  2042.   const Stats &doppel = Doppel::get_stats();
  2043.   const Stats &transmogifier = Transmogifier::get_stats();
  2044.   const Stats &medKit = MedKit::get_stats();
  2045.   const Stats &shield = Shield::get_stats();
  2046.   const Stats &bomb = Bomb::get_stats();
  2047.   const Stats &creature = Creature::get_stats();
  2048.   const Stats &enforcer = Enforcer::get_stats();
  2049.   const Stats &frog = Frog::get_stats();
  2050.   const Stats &hero = Hero::get_stats();
  2051.   const Stats &ninja = Ninja::get_stats();
  2052.   const Stats &alien = Alien::get_stats();
  2053.   const Stats &chopperBoy = ChopperBoy::get_stats();
  2054.   const Stats &lemming = Lemming::get_stats();
  2055.  
  2056.   cout << setprecision(3) << endl
  2057.   << "-----------------------STATISTICS-----------------------" << endl
  2058.   << "Shots fired:                               " 
  2059.   << shot.get_creations() << endl
  2060.   << "Grenades thrown:                           " 
  2061.   << grenade.get_creations() << endl
  2062.   << "Doppelgangers used:                        " 
  2063.   << doppel.get_uses() << endl
  2064.   << "Transmogifiers used:                       " 
  2065.   << transmogifier.get_uses() << endl
  2066.   << "MedKits used:                              " 
  2067.   << medKit.get_uses() << endl
  2068.   << "Shields used:                              " 
  2069.   << shield.get_uses() << endl
  2070.   << "Bombs exploded:                            " 
  2071.   << bomb.get_uses() << endl
  2072.   << "Creatures killed (average lifespan):       " 
  2073.   << creature.get_deaths() << "  (" << creature.get_ave_lifespan() 
  2074.   << " sec)" << endl
  2075.   << "   Enforcers:                              " 
  2076.   << enforcer.get_deaths() 
  2077.   << "  (" << enforcer.get_ave_lifespan() << " sec)" << endl
  2078.   << "   Frogs:                                  " << frog.get_deaths()
  2079.   << "  (" << frog.get_ave_lifespan() << " sec)" << endl
  2080.   << "   Heros:                                  " << hero.get_deaths()
  2081.   << "  (" << hero.get_ave_lifespan() << " sec)" << endl
  2082.   << "   Ninjas:                                 " << ninja.get_deaths()
  2083.   << "  (" << ninja.get_ave_lifespan() << " sec)" << endl
  2084.   << "   Aliens:                                 " << alien.get_deaths()
  2085.   << "  (" << alien.get_ave_lifespan() << " sec)" << endl
  2086.   << "   ChopperBoys:                            " 
  2087.   << chopperBoy.get_deaths()
  2088.   << "  (" << chopperBoy.get_ave_lifespan() << " sec)" << endl
  2089.   << "   Lems:                                   " 
  2090.   << lemming.get_deaths()
  2091.   << "  (" << lemming.get_ave_lifespan() << " sec)" << endl
  2092.   << "Highest level:                             " << levelHighest << endl;
  2093. }
  2094.  
  2095.  
  2096.  
  2097. void Game::refill_enemies()
  2098. {
  2099.   int diff = enemiesNum - locator.enemies_alive();
  2100.   assert(diff >= 0);
  2101.   
  2102.   for (int n = 0; n < diff; n++)
  2103.     create_enemy();
  2104. }
  2105.  
  2106.  
  2107.  
  2108. void Game::hive_refill_enemies()
  2109. {
  2110.   int diff = SCENARIO_HIVE_ALIENS - locator.enemies_alive();
  2111.   assert(diff >= 0);
  2112.  
  2113.   for (int n = 0; n < diff; n++)
  2114.     create_enemy(enemy_physical(A_Alien));
  2115. }
  2116.  
  2117.  
  2118.  
  2119. void Game::flag_refill_enemies()
  2120. {
  2121.   int diff = SCENARIO_FLAG_ENEMIES - locator.enemies_alive();
  2122.   assert(diff >= 0);
  2123.   
  2124.   for (int n = 0; n < diff; n++)
  2125.     create_enemy();
  2126. }
  2127.  
  2128.  
  2129.  
  2130. void Game::lemmings_refill_enemies()
  2131. {
  2132.   int diff = SCENARIO_LEMMINGS_ENEMIES - locator.enemies_alive();
  2133.   assert(diff >= 0);
  2134.   
  2135.   // Change the num argument to enemy_physical if this list is changed.
  2136.   int list[] = {A_Ninja,A_Hero,A_ChopperBoy};
  2137.  
  2138.   for (int n = 0; n < diff; n++)
  2139.     create_enemy(enemy_physical(list,3));
  2140. }
  2141.  
  2142.  
  2143.  
  2144. PhysicalP Game::create_enemy(PhysicalP obj)
  2145. {
  2146.   if (!obj)
  2147.     obj = enemy_physical();
  2148.  
  2149.   IntelOptions ops;
  2150.   ops.harmless = intelHarmless;
  2151.   ops.classFriends = (style != UIsettings::KILL);
  2152.   ops.psychotic = obj->get_class_id() == A_Enforcer || 
  2153.     obj->get_class_id() == A_Alien ||
  2154.       obj->get_class_id() == A_FireDemon;
  2155.   
  2156.   ostrstream name;
  2157.   name << "Machine-" << (enemyNameCount++) << ends;
  2158.   char *nameStr = name.str();
  2159.   EnemyP enemy = new Enemy(&world,&locator,nameStr,&ops,
  2160.                  ITharmless | ITclassFriends | ITpsychotic);
  2161.   assert(enemy);
  2162.   delete nameStr;
  2163.   locator.register_enemy(enemy);
  2164.  
  2165.   locator.add(obj);
  2166.   obj->set_intel(enemy);
  2167.  
  2168.   return obj;
  2169. }
  2170.  
  2171.  
  2172.  
  2173. void Game::demo_setup()
  2174. {
  2175.   // Choose between different demos.
  2176.   switch (Utils::choose(6))  
  2177.     {
  2178.     case 0:  // A bunch of Heros and an Alien.
  2179.       {
  2180.     for (int n = 0; n < 10; n++)
  2181.       {
  2182.         ostrstream name;
  2183.         name << "Enemy-" << n << ends;
  2184.         IntelOptions ops;
  2185.         ops.harmless = True;
  2186.         EnemyP enemy = new Enemy(&world,&locator,name.str(),
  2187.                        &ops,ITharmless);
  2188.         assert(enemy);
  2189.         delete name.str();
  2190.         locator.register_enemy(enemy);
  2191.         
  2192.         Pos pos = world.empty_rect(Hero::get_size_max());
  2193.         PhysicalP obj = new Hero(&world,&locator,pos);
  2194.         assert(obj);
  2195.         locator.add(obj);
  2196.         obj->set_intel(enemy);
  2197.       }
  2198.     IntelOptions ops;
  2199.     ops.psychotic = True;
  2200.     EnemyP enemy = new Enemy(&world,&locator,"killer",&ops,ITpsychotic);
  2201.     assert(enemy);
  2202.     locator.register_enemy(enemy);
  2203.     Pos pos = world.empty_rect(Alien::get_size_max());
  2204.     PhysicalP obj = new Alien(&world,&locator,pos);
  2205.     assert(obj);
  2206.     locator.add(obj);
  2207.     obj->set_intel(enemy);
  2208.       }
  2209.       break;
  2210.     case 1: // Hero, FThrower, and a bunch of Frogs (does not mean Frenchmen).
  2211.       {
  2212.     for (int n = 0; n < 15; n++)
  2213.       {
  2214.         ostrstream name;
  2215.         name << "Enemy-" << n << ends;
  2216.         IntelOptions ops;
  2217.         ops.psychotic = Utils::coinFlip();
  2218.         EnemyP enemy = new Enemy(&world,&locator,name.str(),
  2219.                        &ops,ITpsychotic);
  2220.         assert(enemy);
  2221.         delete name.str();
  2222.         locator.register_enemy(enemy);
  2223.         
  2224.         Pos pos = world.empty_rect(Frog::get_size_max());
  2225.         Id invalid;
  2226.         PhysicalP obj = new Frog(&world,&locator,pos,invalid);
  2227.         assert(obj);
  2228.         locator.add(obj);
  2229.         obj->set_intel(enemy);
  2230.       }
  2231.  
  2232.     EnemyP enemy = new Enemy(&world,&locator,"killer",NULL,0);
  2233.     assert(enemy);
  2234.     locator.register_enemy(enemy);
  2235.     Pos pos = world.empty_rect(Hero::get_size_max());
  2236.     PhysicalP obj = new Hero(&world,&locator,pos);
  2237.     assert(obj);
  2238.     locator.add(obj);
  2239.     obj->set_intel(enemy);
  2240.     
  2241. //    pos = world.empty_rect(FThrower::get_size_max());
  2242.     PhysicalP fThrower = new FThrower(&world,&locator,pos);
  2243.     locator.add(fThrower);
  2244.       }
  2245.       break;
  2246.     case 2: // A bunch of Enforcers.
  2247.       {
  2248.     for (int n = 0; n < 10; n++)
  2249.       {
  2250.         ostrstream name;
  2251.         name << "Enemy-" << n << ends;
  2252.         IntelOptions ops;
  2253.         ops.classFriends = False;
  2254.         ops.psychotic = True;
  2255.         EnemyP enemy = new Enemy(&world,&locator,name.str(),
  2256.                        &ops,ITclassFriends|ITpsychotic);
  2257.         assert(enemy);
  2258.         delete name.str();
  2259.         locator.register_enemy(enemy);
  2260.         
  2261.         Pos pos = world.empty_rect(Enforcer::get_size_max());
  2262.         PhysicalP obj = new Enforcer(&world,&locator,pos);
  2263.         assert(obj);
  2264.         locator.add(obj);
  2265.         obj->set_intel(enemy);
  2266.       }
  2267.       }
  2268.       break;
  2269.     case 3: // A bunch of Ninjas.
  2270.       {
  2271.     for (int n = 0; n < 10; n++)
  2272.       {
  2273.         ostrstream name;
  2274.         name << "Enemy-" << n << ends;
  2275.         IntelOptions ops;
  2276.         ops.classFriends = False;
  2277.         EnemyP enemy = new Enemy(&world,&locator,name.str(),
  2278.                        &ops,ITclassFriends);
  2279.         assert(enemy);
  2280.         delete name.str();
  2281.         locator.register_enemy(enemy);
  2282.         
  2283.         Pos pos = world.empty_rect(Ninja::get_size_max());
  2284.         PhysicalP obj = new Ninja(&world,&locator,pos);
  2285.         assert(obj);
  2286.         locator.add(obj);
  2287.         obj->set_intel(enemy);
  2288.       }
  2289.     Pos pos = world.empty_rect(Chainsaw::get_size_max());
  2290.     PhysicalP obj = new Chainsaw(&world,&locator,pos);
  2291.     locator.add(obj);
  2292.       }
  2293.       break;
  2294.     case 4: // drop weights 
  2295.       {
  2296.     for (int n = 0; n < 36; n++)
  2297.       {
  2298.         Pos pos(32 + 16 * n,16 * 6);
  2299.         Pos pos2(32 + 16 * n,32);
  2300.         PhysicalP p = new Weight(&world,&locator,pos);
  2301.         PhysicalP p2 = new Bomb(&world,&locator,pos2);
  2302.         ((ItemP)p2)->use(NULL);
  2303.  
  2304.         Vel vel(0,-12);
  2305.         ((MovingP)p)->set_vel_next(vel);
  2306.         locator.add(p);
  2307.         locator.add(p2);
  2308.       }        
  2309.  
  2310.     for (int m = 0; m < 10; m++)
  2311.       {
  2312.         ostrstream name;
  2313.         name << "Enemy-" << m << ends;
  2314.         EnemyP enemy = new Enemy(&world,&locator,name.str(),
  2315.                        NULL,ITnone);
  2316.         assert(enemy);
  2317.         delete name.str();
  2318.         locator.register_enemy(enemy);
  2319.         
  2320.         Pos pos(32 + Utils::choose(16 * 36),16 * 12);
  2321.         PhysicalP obj;
  2322.         switch (Utils::choose(3)) {
  2323.         case 0:
  2324.           obj = new Ninja(&world,&locator,pos);
  2325.           break;
  2326.         case 1:
  2327.           obj = new Hero(&world,&locator,pos);
  2328.           break;
  2329.         case 2:
  2330.           {
  2331.         Id invalid;
  2332.         obj = new Frog(&world,&locator,pos,invalid);
  2333.           }
  2334.           break;
  2335.         };
  2336.         assert(obj);
  2337.         locator.add(obj);
  2338.         obj->set_intel(enemy);
  2339.       }
  2340.       }
  2341.       break;
  2342.     case 5: // Ninjas and ChopperBoys.
  2343.       {
  2344.     for (int n = 0; n < 10; n++)
  2345.       {
  2346.         ostrstream name;
  2347.         name << "Enemy-" << n << ends;
  2348.         IntelOptions ops;
  2349.         ops.classFriends = False;
  2350.         EnemyP enemy = new Enemy(&world,&locator,name.str(),
  2351.                        &ops,ITclassFriends);
  2352.         assert(enemy);
  2353.         delete name.str();
  2354.         locator.register_enemy(enemy);
  2355.         
  2356.         PhysicalP obj;
  2357.         Pos pos;
  2358.         if (n % 2)
  2359.           {
  2360.         pos = world.empty_rect(Ninja::get_size_max());
  2361.         obj = new Ninja(&world,&locator,pos);
  2362.           }
  2363.         else
  2364.           {
  2365.         pos = world.empty_rect(ChopperBoy::get_size_max());
  2366.         obj = new ChopperBoy(&world,&locator,pos);
  2367.           }
  2368.         assert(obj);
  2369.         locator.add(obj);
  2370.         obj->set_intel(enemy);
  2371.       }
  2372.     for (n = 0; n < 5; n++)
  2373.       {
  2374.         Pos pos = world.empty_rect(Launcher::get_size_max());
  2375.         PhysicalP obj = new Launcher(&world,&locator,pos);
  2376.         assert(obj);
  2377.         locator.add(obj);
  2378.       }
  2379.  
  2380.       }
  2381.       break;
  2382.     default:
  2383.       assert(0);
  2384.     };
  2385. }
  2386.  
  2387.  
  2388.  
  2389. void Game::off_clock_kill(PhysicalP p)
  2390. {
  2391. //  cout << "attempting to kill " << p->identify() << endl;
  2392.  
  2393.   p->set_quiet_death();
  2394.   if (!p->die_called())
  2395.     {
  2396.       p->kill_self();
  2397.       p->die();
  2398.     }
  2399. }
  2400.  
  2401.